/*
    Project:        Home Power Control
    File:           HPCStation.cpp
    Author:         christian@karunamusic.at
    Date:           12.2014
    Description:    A collection of units grouped together - main class for the station.
 */

#include <exception>
#include <iostream>
#include <sstream>
#include <boost/program_options.hpp>
#include <wiringPi.h>
#include "globals.h"
#include "version.h"
#include "HPCDatabase.h"
#include "HPCStation.h"
#include "HPCLogScreen.h"

namespace po = boost::program_options;
namespace av = AutoVersion;
using namespace std;


HPCStation::HPCStation( int argc, char *argv[] ) : m_DB(nullptr), m_LogScreen(nullptr)
{
    PROFILE_THIS;

    po::options_description desc( "Allowed options" );
    desc.add_options()
    ( "database,d" , po::value<string>(), "databasename to connect to." )
    ( "host,h"     , po::value<string>(), "hostname (or ip-address) of database-server" )
    ( "user,u"     , po::value<string>(), "username for database connection" )
    ( "password,p" , po::value<string>(), "password of the database user" )
    ( "slv"        , po::value<unsigned int>()->default_value(((unsigned int)fatal)+1), "screen log verbosity 0(off)-6(trace), default: 1(fatal)" )
    ( "flv"        , po::value<unsigned int>()->default_value(((unsigned int)info )+1), "file log verbosity 0(off)-6(trace), default 4(info)" )
    ( "help,?"     ,                      "display help message" )
    ( "version,V"  ,                      "display version information" )
    ;

    po::variables_map vm;
    try
    {
        stringstream cfg;
        cfg << argv[0] << ".conf";
        ifstream settings_file(cfg.str());

        po::store ( po::parse_command_line( argc,argv,desc     ), vm );
        po::store ( po::parse_config_file ( settings_file,desc ), vm );
        po::notify( vm );
    }
    catch ( exception &e )
    {
        LOG( trace,e.what() );
        cerr << e.what() << endl << desc << endl;
        throw runtime_error( "" );
    }

    string  database,
            host,
            user,
            password;

    unsigned int slvl = (unsigned int)fatal;
    unsigned int flvl = (unsigned int)info;

    if ( vm.count("database") )
    {
        database = vm["database"].as<string>();
    }
    if ( vm.count("host") )
    {
        host = vm["host"].as<string>();
    }
    if ( vm.count("user") )
    {
        user = vm["user"].as<string>();
    }
    if ( vm.count("password") )
    {
        password = vm["password"].as<string>();
    }
    if ( vm.count("slv") )
    {
        slvl = vm["slv"].as<unsigned int>();
        if ( slvl )
        {
            slvl--;
            if ( slvl > (unsigned int)trace )
                slvl = (unsigned int)trace;
        }
    }
    if ( vm.count("flv") )
    {
        flvl = vm["flv"].as<unsigned int>();
        if ( flvl )
        {
            flvl--;
            if ( flvl > (unsigned int)trace )
                flvl = (unsigned int)trace;
        }
    }
    if ( vm.count("help") )
    {
        cout << desc << endl;
        throw runtime_error( "" );
    }
    if ( vm.count("version") )
    {
        cout << "Version  " << av::FULLVERSION_STRING << " " << av::STATUS << endl
             << "Revision " << av::SVN_REVISION << " from " << av::DATE << "." << av::MONTH << "." << av::YEAR << endl;
        throw runtime_error( "" );
    }

    if ( slvl )
    {
        m_LogScreen = new HPCLogScreen( (TLogLevel)slvl );
    }
    if ( flvl )
    {
        stringstream lf;
        lf << argv[0] << ".log";
        m_LogFile   = new HPCLogFile  ( (TLogLevel)flvl, lf.str() );
    }

    LOG( fatal, "***** starting HomePowerControl *****" );
    LOG( fatal, "      screen verbosity level: " << slvl );
    LOG( fatal, "      file   verbosity level: " << flvl );

    if ( wiringPiSetup() == -1 )
    {
        THROW( "wiringPiSetup() failed!" );
    }

    try
    {
        stringstream df;
        df << argv[0];
        m_DB = new HPCDatabase( host,user,password,database,df.str() );
        m_DB->createUnits( *this );
    }
    catch ( exception &e )
    {
        LOG( trace, e.what() );
        throw;
    }
}

HPCStation::~HPCStation()
{
    PROFILE_THIS;

    for ( HPCUnit* unit: m_Units )
    {
        delete unit;
    }
    if ( m_DB )
    {
        delete m_DB;
    }

    LOG( fatal, "***** HomePowerControl ended *****" );
}

HPCStation& HPCStation::operator += ( HPCUnit* unit )
{
    PROFILE_THIS;
    m_Units.push_back( unit );

    return *this;
}
